package com.ming.ultlight.ble

import android.annotation.SuppressLint
import android.app.Service
import android.bluetooth.*
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.util.Log
import com.ming.ultlight.DevicesAdapter
import com.ming.ultlight.utils.ByteUtils




private const val TAG = "ult_BluetoothLeService"

class BluetoothLeService : Service() {

    //蓝牙适配器
    private var bluetoothAdapter: BluetoothAdapter? = null
    //蓝牙GATT Service
    private var bluetoothGatt: BluetoothGatt? = null
    private var writeNotifyGattCharacteristic: BluetoothGattCharacteristic? = null  // write && notify
    //连接状态 初始化未连接
    private var connectionState = STATE_DISCONNECTED
    //设备扫描状态
    private var mScanning: Boolean = false

    //蓝牙设备适配器
    var ledeviceAdapter: DevicesAdapter = DevicesAdapter(this)

    //写队列
    var writeQueue:ArrayList<ByteArray> = arrayListOf()

    // 蓝牙设备扫描回调函数 处理设备列表
    // todo 后面若指定了设备的信息  则可以精确过滤
    private val leScanCallback: ScanCallback = object : ScanCallback() {
        @SuppressLint("MissingPermission")
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)
            if (result == null) {
                Log.i(TAG, "onScanResult: result is null")
                return
            }
            if(result.device.name == null){
                Log.i(TAG, "device name is null")
                return
            }
            Log.i(TAG, "onScanResult: devicename=${result.device.name} address=${result.device.address} info:${result.scanRecord.toString()}")
            ledeviceAdapter.addDevice(result.device)
            ledeviceAdapter.notifyDataSetChanged()
        }

        override fun onBatchScanResults(results: List<ScanResult?>?) {
            super.onBatchScanResults(results)
            Log.i(TAG, "onBatchScanResults")
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            Log.i(TAG, "onScanFailed:${errorCode}")

        }
    }
    //初始化adapter
    fun initialize(): Boolean {
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        bluetoothAdapter = bluetoothManager.adapter
        if (bluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.")
            return false
        }
        return true
    }

    override fun onCreate() {
        super.onCreate()
        initialize()
        Log.d(TAG, "service created")
    }

    // 蓝牙扫描程序
    @SuppressLint("MissingPermission")
    fun scanLeDevice(enable: Boolean) {
        val bluetoothLeScanner: BluetoothLeScanner = bluetoothAdapter!!.bluetoothLeScanner;
        when (enable) {
            true -> {
                // Stops scanning after a pre-defined scan period.
                Handler(Looper.getMainLooper()).postDelayed({
                    mScanning = false
                    bluetoothLeScanner.stopScan(leScanCallback)
                }, SCAN_PERIOD)
                mScanning = true
                bluetoothLeScanner.startScan(leScanCallback)
            }
            else -> {
                mScanning = false
                bluetoothLeScanner.stopScan(leScanCallback)
            }
        }
    }

    //连接设备
    fun connect(position: Int): Boolean {
        val device = ledeviceAdapter.getItem(position) as BluetoothDevice
        return connect(device.address)
    }

    //连接设备
    @SuppressLint("MissingPermission")
    fun connect(address: String): Boolean {
        bluetoothAdapter?.let { adapter ->
            try {
                val device = adapter.getRemoteDevice(address)
                // connect to the GATT server on the device
                bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback)
                return true
            } catch (exception: IllegalArgumentException) {
                Log.w(TAG, "Device not found with provided address.")
                return false
            }
        } ?: run {
            Log.w(TAG, "BluetoothAdapter not initialized")
            return false
        }
    }

    //GATT Service 回调函数
    private val bluetoothGattCallback = object : BluetoothGattCallback() {
        @SuppressLint("MissingPermission")
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // successfully connected to the GATT Server
                connectionState = STATE_CONNECTED
                broadcastUpdate(ACTION_GATT_CONNECTED)
                // 提升传输效率
                gatt?.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH)
                // Attempts to discover services after successful connection.
                bluetoothGatt?.discoverServices()
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                // disconnected from the GATT Server
                connectionState = STATE_DISCONNECTED
                broadcastUpdate(ACTION_GATT_DISCONNECTED)
            }
        }

        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                discoverGattServices(gatt?.services)
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED)
            } else {
                Log.w(TAG, "onServicesDiscovered received: $status")
            }
        }

        override fun onCharacteristicRead(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            status: Int
        ) {
            Log.d(TAG, "onCharacteristicRead...")
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic)
            }
        }

        override fun onCharacteristicChanged(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic
        ) {
            Log.d(TAG, "onCharacteristicChanged...")
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic)
        }

        override fun onCharacteristicWrite(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?,
            status: Int
        ) {
            Log.i(TAG, "write callback: status=${status}")
        }
    }

    //broadcast to activity
    private fun broadcastUpdate(action: String) {
        Log.d(TAG, "broadcastUpdate ${action.toString()}")
        val intent = Intent(action)
        sendBroadcast(intent)
    }

    private var packData: ByteArray = byteArrayOf()
    private var waitEnd: Boolean = false

    private fun broadcastUpdate(action: String, characteristic: BluetoothGattCharacteristic) {
        Log.d(TAG, "broadcastUpdate ${action.toString()} from ${characteristic.uuid.toString()}")

        val data: ByteArray? = characteristic.value
        if(data == null || data.isEmpty()){
            return
        }
        val hexString: String = data.joinToString(separator = " ") {
            String.format("%02X", it)
        }
        Log.d(TAG, "received : $data\n$hexString")

        //数据到达 解析蓝牙数据
        for (i in data.indices){
            if(data[i].toInt() == 0x00){
                if(waitEnd){
                    packData += byteArrayOf(data[i])
                    //收齐完整的包 进行处理
                    var intent = Intent(DATA_BLE_PKG)
                    intent.putExtra(EXTRA_DATA, packData)
                    sendBroadcast(intent)
                    packData = byteArrayOf()  //清空
                    waitEnd = false
                }else{
                    //丢弃之前的错误包
                    packData = byteArrayOf()
                    packData += byteArrayOf(data[i])
                    waitEnd = true
                }
            }else{
                packData += byteArrayOf(data[i])
            }
        }
    }

    fun getSupportedGattServices(): List<BluetoothGattService>? {
        return bluetoothGatt?.services
    }

    // 发现gatt Service
    private fun discoverGattServices(gattServices: List<BluetoothGattService>?) {
        if (gattServices == null) return
        // Loops through available GATT Services.
        gattServices.forEach { gattService ->
            val gattCharacteristics = gattService.characteristics
            // Loops through available Characteristics.
            gattCharacteristics.forEach { gattCharacteristic ->
                Log.d(TAG, "serviceInfo:${gattCharacteristic.permissions}  desc:${gattCharacteristic.descriptors} property:${gattCharacteristic.properties}")
                if((gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_WRITE) == BluetoothGattCharacteristic.PROPERTY_WRITE
                    && (gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY) == BluetoothGattCharacteristic.PROPERTY_NOTIFY){
                    // 可读写
                    writeNotifyGattCharacteristic = gattCharacteristic
                    //todo 已准备好
                }
            }
        }
        if(writeNotifyGattCharacteristic == null){
            Log.d(TAG, "no service for write && notify!!")
            return
        }
        enableCharacteristicNotification()
    }

    @SuppressLint("MissingPermission")
    fun enableCharacteristicNotification(){
        val success: Boolean = this.bluetoothGatt!!.setCharacteristicNotification(writeNotifyGattCharacteristic, true)
        Log.i(TAG, "setCharactNotify: $success")
        Log.i(TAG, "desp:${writeNotifyGattCharacteristic?.descriptors}")
        writeNotifyGattCharacteristic?.descriptors?.forEach {
            Log.i(TAG, it.uuid.toString())
        }
    }

    //写数据
    fun writeData(data: String) :Boolean{
        if(writeNotifyGattCharacteristic == null){
            return false
        }
        var data = ByteUtils.hexStringToBytes(data)
//        writeQueue.add(data)
//        return writeToBle()
        writeNotifyGattCharacteristic!!.value = data
        return writeCharacteristic(writeNotifyGattCharacteristic!!)
    }

    //写数据
    fun writeData(byteMsg:ByteArray): Boolean{
        if(writeNotifyGattCharacteristic == null){
            return false
        }
//        writeQueue.add(byteMsg)
//        writeToBle()
//        return true

        writeNotifyGattCharacteristic!!.value = byteMsg
        var ret = writeCharacteristic(writeNotifyGattCharacteristic!!)
        if (ret){
            Log.i(TAG, "send to ble success!")
        }else{
            Log.e(TAG, "send to ble Fail!")
        }
        return ret
    }

    private var isWriting:Boolean = false
    private fun writeToBle():Boolean{
        if(isWriting){
            return true
        }
        isWriting = true
        while (true){
            if(writeQueue.isEmpty()){
                isWriting = false
                return true
            }
            var data = writeQueue.removeAt(0)
            writeNotifyGattCharacteristic!!.value = data
            writeCharacteristic(writeNotifyGattCharacteristic!!)
        }
        return false
    }


    @SuppressLint("MissingPermission")
    private fun writeCharacteristic(characteristic: BluetoothGattCharacteristic):Boolean {
        bluetoothGatt?.let { gatt ->
            if(gatt.writeCharacteristic(characteristic)){
                Log.d(TAG, "write success!")
                return  true
            }else{
                Log.d(TAG, "write fail...")
                return false
            }
        } ?: run {
            Log.w(TAG, "BluetoothGatt not initialized")
            return false
        }
    }

    private val binder = LocalBinder()

    override fun onBind(intent: Intent): IBinder? {
        return binder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        close()
        return super.onUnbind(intent)
    }

    @SuppressLint("MissingPermission")
    private fun close() {
        bluetoothGatt?.let { gatt ->
            gatt.close()
            bluetoothGatt = null
        }
    }

    inner class LocalBinder : Binder() {
        fun getService() : BluetoothLeService {
            return this@BluetoothLeService
        }
    }

    companion object {
        const val ACTION_GATT_CONNECTED =
            "com.ming.bluetooth.le.ACTION_GATT_CONNECTED"
        const val ACTION_GATT_DISCONNECTED =
            "com.ming.bluetooth.le.ACTION_GATT_DISCONNECTED"
        const val ACTION_GATT_SERVICES_DISCOVERED =
            "com.ming.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"
        const val ACTION_DATA_AVAILABLE =
            "com.ming.bluetooth.le.ACTION_DATA_AVAILABLE"
        const val DATA_BLE_PKG =
            "com.ming.bluetooth.le.Data_BLE_PKG"
        private const val STATE_DISCONNECTED = 0
        private const val STATE_CONNECTED = 2

        // 每次设备扫描时长
        private const val SCAN_PERIOD: Long = 10000

        const val EXTRA_DATA = "EXTRA_DATA"

        const val OTA_UPGRADE_SEND = "light_ota_upgrade_send" //固件升级发送
        const val OTA_UPGRADE_RESP = "light_ota_upgrade_resp" //固件升级响应
        const val OTA_UPGRADE_PROGRESS = "light_ota_upgrade_progress" //固件升级进度通知



    }

}